%***********************************************************
% CS 229 Machine Learning
% Project, Ground truth data generation
%-----------------------------------------------------------
% Date : November 13, 2010
%***********************************************************

clear all;

addpath(genpath('./LIBSVM/'))

%**************************************************************************
%Input parameters - test
outputwidth = 320;
outputheight = 180;
Wmax = 640;
Hmax = 360;
scale_conversion_factor_tracking = 1.5;

lecturer_tracking_scale_factor = 640/2560;
saliency_tracking_scale_factor = 640/1920;

load groundTruth.dat;
load lecturer.dat;
load saliency.dat;
load boards.dat;
load panning.mat;
%**************************************************************************


dataA = groundTruth;

% The required frame rate is 33 ms per frame. Our data contains observations
% that are taken at time intervals that are multiples of 100 ms. Thus, we
% need to interpolate these observations.

size(dataA)

%--------------------------------------------------------------------------
% Interpolate data
interpolatedTimeStamps = (dataA(1,1):100/3:dataA(size(dataA,1),1));
newDataA = zeros(size(interpolatedTimeStamps',1),3);
newDataA(:,1) = interpolatedTimeStamps';
newDataA(:,2) = (interp1(dataA(:,1)', dataA(:,2)', interpolatedTimeStamps))'./scale_conversion_factor_tracking+10;
newDataA(:,3) = (interp1(dataA(:,1)', dataA(:,3)', interpolatedTimeStamps))'./scale_conversion_factor_tracking+10;

%--------------------------------------------------------------------------
%Adjustment for camera border case
%newDataA(:,2) = min(max(floor(newDataA(:,2) - outputwidth/2),1),Wmax-outputwidth) + outputwidth/2;
%newDataA(:,3) = min(max(floor(newDataA(:,3) - outputheight/2),1),Hmax-outputheight) +outputheight/2 ;
%--------------------------------------------------------------------------

%==========================================================================================
y = newDataA(:,2);
y = smooth(y,150);

% Prepare features first
size(lecturer)
size(saliency)
size(y)

% Scale vectors
%lecuturer feature adjustment
lecturer = lecturer * lecturer_tracking_scale_factor;
lecturer(:,2) = min(max(floor(lecturer(:,2) - outputwidth/2),1),Wmax-outputwidth) + outputwidth/2 ;
lecturer(:,3) = min(max(floor(lecturer(:,3) - outputheight/2),1),Hmax-outputheight) +outputheight/2  ;

%saliency feature adjustment
saliency = saliency *  saliency_tracking_scale_factor;
%saliency(:,2) = saliency(:,2) + outputwidth/2;
%saliency(:,3) = saliency(:,3) + outputheight/2;

minFrameOffset = 1;
minError = 1e999;
trainMSEArr = [];
testMSEArr = [];
frame_offset_arr = [];
cvRate_arr = [];

%Prepare features
numPoints = 50000;
frame = 300; % Sliding window size
step = round(frame/15); % Step size. Num steps in this case = 15
X = PreparePanFeatures(1, numPoints, frame,step, lecturer, saliency,boards  );
d = X';
l = panning_indicator;

%CV training

%==========================================================================

bestcv = 0;
% for frame_ind = 5:12
% for log2c = 2.9
%     for log2g = 0.9
%         frame = 2^frame_ind;
%       step = round(frame/20);
%       tic
%       X = PreparePanFeatures(1, numPoints, frame,step, lecturer, saliency,boards  );
%           d = X';
%           toc
%           tic
%         cmd = ['-t 2 -v 5 -c ', num2str(2^log2c), ' -g ', num2str(2^log2g)];
%         cv = svmtrain(l, d, cmd);
%         toc
%        % [precision, recall, accuracy] = computePrecisionRecall(predicted_panning_label, l(testing_seq));
%       %  fmeasure = 2*(precision*recall)/(precision+recall);
%       %  if (fmeasure >= bestf),
%         if(cv>bestcv)
%             bestcv = cv; bestc = 2^log2c; bestg = 2^log2g; bestframe = frame;
%             fprintf('%g %g %g %g (best c=%g, g=%g, rate=%g)\n', log2c, log2g, bestframe, cv, bestc, bestg, bestcv);
%         end
%     end
% end
% end

%==========================================================================

bestc = 2^-1.1;
bestg = 2^0.9;

training_seq = 10001:50000;
testing_seq = 1:10000;
bestf = -1;
for frame = 500
    for numsteps = 5
         for log2c = 0.95 % SVM Parameter
             for log2g = 1.80 % SVM Parameter
               % frame = 2^frame_ind;
                step = round(frame/numsteps);
                X = PreparePanFeatures(1, numPoints, frame,step, lecturer, saliency, boards);
                d = X';
                tic
                cmd = ['-t 2 -c ', num2str(2^log2c), ' -g ', num2str(2^log2g)];
                model =  svmtrain(l(training_seq), d(training_seq,:) ,cmd);
                
                [predicted_panning_label, accuracy, decision_values] = svmpredict(l(testing_seq), d(testing_seq,:), model);
                [precision, recall, accuracy] = computePrecisionRecall(predicted_panning_label, l(testing_seq));

                toc
                    
                fmeasure = 2*(precision*recall)/(precision+recall);
                if (fmeasure >= bestf),
                    bestf = fmeasure; bestc = 2^log2c; bestg = 2^log2g; bestframe = frame; beststep= round(frame/numsteps); bestmodel = model;
                    bestprecision = precision;
                    bestrecall = recall;
                    
                    temp_result = [log2c, log2g, frame,round(frame/numsteps) ,fmeasure, ...
                        bestc, bestg,  precision, recall];
                    
                    %in case crash/hang
                    save('temp_result.mat','temp_result');

                end
                      fprintf('[Current: %g %g #frame:%g #features: %g fmeasure: %g(best c=%g, g=%g ) PR: %g RC: %g ]\n',...
                        log2c, log2g, frame,round(frame/numsteps) ,fmeasure, ...
                        bestc, bestg,  precision, recall);
                    
                      fprintf('[best: #frame:%g #features: %g fmeasure: %g(best c=%g, g=%g) PR: %g RC: %g ]\n',...
                        bestframe,beststep ,bestf, ...
                        bestc, bestg, bestprecision, bestrecall);
                
             end
         end
    end
end

X = PreparePanFeatures(1, numPoints, bestframe,beststep, lecturer, saliency,boards  );
d = X';
[predicted_panning_label, accuracy, decision_values] = svmpredict(l(testing_seq), d(testing_seq,:), bestmodel);

t=testing_seq;

figure(101)
plot(t,50*l(t),t,50*predicted_panning_label, t,y(t)-mean(y(t)));
legend('Ground truth','Prediction','Actual Trajectory', 'saliency', 'lecturer')

% The predicted panning labels are quite noisy in places where we expect a
% '1'. Level these oscillations off to '1'. We do this in two steps:
% 1. Go over the data once and change all groups of -1's which are thinner
% than 200 frames in width to 1.
% 2. Now, go over the data again, and remove all groups of 1's that are
% less than 50 frames in width.

last_one = 0;
for i = 1:size(predicted_panning_label, 1)
    if (predicted_panning_label(i,1) == 1)
        if (last_one > 0 && (i - last_one) <= 200)
            predicted_panning_label(last_one:i,1) = 1;
        end
        last_one = i;
    end
end
        
last_minus_one = 0;
for i = 1:size(predicted_panning_label, 1)
    if (predicted_panning_label(i,1) == -1)
        if (last_minus_one > 0 && (i - last_minus_one) <= 50)
            predicted_panning_label(last_minus_one:i,1) = -1;
        end
        last_minus_one = i;
    end
end


[precision, recall, accuracy] = computePrecisionRecall(predicted_panning_label, l(testing_seq));                

figure(100)

% plot(t,50*l(t));
% legend('Ground truth')
% 
% figure(100)
% plot(t,50*predicted_panning_label);
% legend('Prediction')
% 
% 
% figure(101)
plot(t,50*l(t),t,50*predicted_panning_label, t,y(t)-mean(y(t)));
legend('Ground truth','Prediction','Actual Trajectory', 'saliency', 'lecturer')
title(['Precision:' num2str(precision) ' recall: ' num2str(recall) ' accuracy: ' num2str(accuracy) ]);

        
save('predicted_panning_label.mat','predicted_panning_label');


